"""
作者：tiandongjun
功能：模拟Hik服务器
版本：
日期：
2019-04-02 1.0：可以运行，接收图片功能
2019-04-04 2.0：解析错误，返回错误
2019-05-10 3.0: 图片目录pics，修改logging打印的内容
2019-08-27 4.0: 图片格式错误返回正常，并保持图片
2019-09-12 5.0: 图片格式错误返回正常，并保持图片
                增加统计图片数量功能
2019-10-14 6.0: 修改logging打印信息，增加Hik
2019-11-1  7.0: logging部分修改
2019-11-22  8.0: response部分修改
2020-04-24  8.1: 增加图片接收时间和shottime之间时间差的计算，用 datetime
2020-12-21  8.2: 解析hik内部数据信息
"""

import http.server
import socketserver
import json
import time
import datetime
import os,logging
import re
import json
from logging.handlers import RotatingFileHandler
import threading
import configparser
import get_hikinfo

VERSION = '8.2'
registerIPs = {}
_running = True
httpd = 0
save_jpg = 0
check_jpg = 0
noresponse = 0
Hiklogging = logging.getLogger('Hik')
loglevel = 1

threadNumsLock=threading.Lock()
allThreads=[]
server_runtime = [0]

class HIKLog():
    def __init__(self):
        pass
    
    def info(self, msg):
        try:
            mylogging.info(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))
            
    def error(self, msg):
        try:
            mylogging.error(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))
    
    def warning(self, msg):
        try:
            mylogging.warning(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))

"""
使用自定义类，再次封装 logging 使用方法
1, 修改 Hiklogging = logging.getLogger('Hik') ==> mylogging = logging.getLogger('Hik')
2, 修改 init_loggingSetHik 中的 Hiklogging ==> mylogging
3, 增加 Hiklogging = HIKLog()
"""  
    
def init_loggingSetHik():
    """
        功能：初始化logging设置，将打印信息分别记录到文件和屏幕上
    :return:
    """
    # 打印到文件
    localtime = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
    logFilename = "./hik/log/" + localtime + "_hik.log"
    logging.basicConfig(level=logging.DEBUG,format='%(asctime)s [line:%(lineno)d] %(filename)s %(levelname)-8s %(message)s') 
    # datefmt='%a, %d %b %Y %H:%M:%S',
    Hiklogging.handlers = []
    ################################################################################################
    #定义一个RotatingFileHandler，最多备份5个日志文件，每个日志文件最大10M
    Rthandler = RotatingFileHandler(logFilename, maxBytes=50 * 1024 * 1024, backupCount=50)
    Rthandler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(filename)s %(levelname)-8s %(message)s') 
    Rthandler.setFormatter(formatter)

    # 打印到屏幕
    '''
    console = logging.StreamHandler()
    console.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(filename)s %(levelname)-8s %(message)s') 
    console.setFormatter(formatter)    
    Hiklogging.addHandler(console)
    '''
    Hiklogging.addHandler(Rthandler)
    #print(Hiklogging.handlers)
    #CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
    
class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        Hiklogging.info(str(self.client_address) +": " + self.requestline)

    def response_Ok(self,url,puid,faceid):
        if os.path.isfile("hik.ini"):
            conf = configparser.ConfigParser()
            conf.read('hik.ini')
            try:                
                infomsg = '返回 hik.ini中定义消息'
                sel = conf.get("sel",'usehttp')
                if sel=='1':
                    r = conf.get("http",'r')
                    expires = conf.get("http",'expires')
                    content_type = conf.get("http",'content-type')
                    LocalTime = conf.get("http",'date')
                    content_dict=conf.get("http",'content')
                    self.send_response_only(int(r))
                    self.send_header("Expires", expires)
                    self.send_header("Content-type", content_type)
                    self.send_header("Date",LocalTime) 
                    content_str =content_dict
                    content_len = len(content_str)
                    self.send_header("Content-Length", str(content_len))
                    self.end_headers()
                    content_bytes = content_str.encode("utf-8")
                    self.wfile.write(content_bytes)  # 返回给client数据 
                    infomsg+=": http: " + r
                else:
                    conn=self.request
                    msg = conf.get("other",'msg')  
                    closesocket = conf.get("other",'closesocket')  
                    infomsg+=": TCP：" + msg  
                    back_data = msg.encode('utf8')
                    conn.sendall(back_data) 
                    if closesocket=='1':
                        conn.close()  
                infomsg +=" ,返回消息时长:" + "%.06f"%(time.time()-self.usetime) + 's'
                Hiklogging.info(str(self.client_address) +": " + infomsg)
            except Exception as e:
                Hiklogging.error(str(self.client_address) +": " + str(e))
            return
        self.send_response_only(200)
        self.send_header("Server", 'Custom tool')#url)
        #self.send_header("PuID",puid)
        #self.send_header("FaceId",faceid)
        self.send_header("Content-type", "application;charset=UTF-8")
        
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        LocalTime = datetime.datetime.now().strftime(GMT_FORMAT)
        #LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        self.send_header("Date",LocalTime)        
     
        content_str ="UploadResult:Result=1"
        content_len = len(content_str)
        self.send_header("Content-Length", str(content_len))
        self.end_headers()
        content_bytes = content_str.encode("utf-8")
        self.wfile.write(content_bytes)  # 返回给client数据
        Hiklogging.info(str(self.client_address) +": "+"200 Upload Success"+" ,返回消息时长:" + "%.06f"%(time.time()-self.usetime) + 's')

    def response_UploadFail(self,reason):
        self.send_response_only(200)
        self.send_header("Reason-Phrase", "Fail")
        self.send_header("Server", 'Custom tool')#self.url)
        #self.send_header("PuID", self.puid)
        #self.send_header("FaceId", self.faceid)
        self.send_header("Content-Type", "application;charset=UTF-8")       
        
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        LocalTime = datetime.datetime.now().strftime(GMT_FORMAT)
        #LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        self.send_header("Date",LocalTime)     
  
        content_str = "UploadResult:Result=0"
        content_str += "Reason=" + reason
        content_len = len(content_str)
        self.send_header("Content-Length", str(content_len))
        self.end_headers()
        content_bytes = content_str.encode("utf-8")
        self.wfile.write(content_bytes)  # 返回给client数据
        Hiklogging.error(str(self.client_address) + ": " + "200 Upload Fail")

    def response_BadRequest(self,reason):
        self.send_response_only(400)
        self.send_header("Reason-Phrase", reason)
        self.send_header("Content-type", "applicatio;charset=UTF-8")
        self.send_header("Content-Length", "0")
        self.end_headers()
        Hiklogging.error(str(self.client_address) +": "+"400 BadRequest")

    def cal_result(self,ipaddr):
        try:
            if ipaddr not in registerIPs.keys(): 
                picPacksum = 1              # 图片数据包总数              
                picSum = self.findPicNums   # 图片数量
                txtSum = self.findTxtNums   # txt数量
                errSum = self.errpicsum     # 错误图片数量
                zeroSum = self.zeropicsum   # 图片大小为0的数量                 
                registerIPs[ipaddr] = [picPacksum, picSum, txtSum,errSum,zeroSum,self.repeatpicsum, self.repeattxtsum]                
                # 图片数据包总数, 图片总数量，txt总数量,错误图片数量,图片大小为0的数量
            else:
                picPacksum = registerIPs[ipaddr][0] + 1
                picSum = registerIPs[ipaddr][1] + self.findPicNums
                txtSum = registerIPs[ipaddr][2] + self.findTxtNums
                errSum = registerIPs[ipaddr][3] + self.errpicsum
                zeroSum = registerIPs[ipaddr][4] + self.zeropicsum                 
                repeatpicsum = registerIPs[ipaddr][5] + self.repeatpicsum                 
                repeattxtsum = registerIPs[ipaddr][6] + self.repeattxtsum                 
                registerIPs[ipaddr] = [picPacksum, picSum, txtSum,errSum,zeroSum,repeatpicsum,repeattxtsum]
            picResult = " {}:\n\t数据包数量:{},图片:{},txt文件:{}\n\t[其中错误图片:{},大小为0的图片:{},重名图片:{},重名txt:{}]".format(\
                    ipaddr,registerIPs[ipaddr][0],registerIPs[ipaddr][1],registerIPs[ipaddr][2],\
                    registerIPs[ipaddr][3],registerIPs[ipaddr][4],registerIPs[ipaddr][5],registerIPs[ipaddr][6])
            Hiklogging.info(str(self.client_address)+": "+ picResult)  
        except Exception as e:
            Hiklogging.error(str(self.client_address) + ": 异常:" + str(e))    
       
    def getThreads(self):
        try:
            threadNumsLock.acquire()     
            msg = "HIK接收消息线程\n"
            msg += 'before :{}个线程,[{}]'.format(len(allThreads), allThreads)
            aliveThreads=[]
            for curthread in allThreads:
                if curthread.is_alive():
                    aliveThreads.append(curthread)
            allThreads.clear()
            allThreads.extend(aliveThreads)
            if threading.current_thread() not in aliveThreads:
                allThreads.append(threading.current_thread())
            msg += '\nafter :{}个线程,[{}]'.format(len(allThreads),allThreads)
            Hiklogging.info(str(self.client_address)+": "+ msg)
            if threadNumsLock.locked():
                threadNumsLock.release()  
        except Exception as e:
            Hiklogging.error(str(self.client_address)+": "+ 'except: ' + str(e))        
        
    def savedata(self, filename, data):    
        # 保存 二进制 文件
        len1 = 0
        try:
            with open(filename, 'wb') as f:
                len1 = f.write(data)
        except Exception as e:
            Hiklogging.error(str(self.client_address)+": " + '写{},出现异常:'.format(filename) + str(e))
        return len1
        
    def do_POST(self): 
        if not _running:
            return    
        self.now = datetime.datetime.now()
        if os.path.isfile("hik.ini"):
            conf = configparser.ConfigParser()
            conf.read('hik.ini')
            closeconn = conf.get("closeconn","close")
            if closeconn == '1':
                conn=self.request
                Hiklogging.info(str(self.client_address) +": " + "关闭连接")
                conn.close()  
                return        
        self.usetime = time.time()            
        self.getThreads()
        
        self.picNums = 0 #图片数量
        self.findPicNums = 0 # 实际发现图片数量
        self.errpicsum = 0 # 错误图片数量0
        self.zeropicsum = 0 # 图片大小为0的数量0
        self.repeatpicsum = 0 # 重名图片数量0
        self.repeattxtsum = 0 # 重名文件数量0
        self.findTxtNums = 0 #
        try:            
            Hiklogging.info(str(self.client_address) +": "+"***上传图片***")            
            """
            POST url://10.90.24.2:8082/abcpuid=123&chan=01&
            zptime=20190402132447787&faceid=10&facescore=0&
            x=0&y=0&width=0&height=0&age=0&sex=0&glass=0&
            end=0&stay=0&picnum=4&remark=0 HTTP/1.0
            """
            self.faceid = self.puid = self.url = self.zptime = ""
            requestline = self.requestline
            if loglevel:
                try:
                    tmp_msg = get_hikinfo.parse_requestline(requestline)
                    Hiklogging.info(str(self.client_address) +": "+ str(requestline) + '\n' + tmp_msg)
                except:
                    pass
            self.faceid = re.compile("faceid=(.*?)&").findall(requestline)
            self.puid = re.compile("puid=(.*?)&").findall(requestline)
            self.url = re.compile("POST (.*?)puid").findall(requestline)
            self.zptime = re.compile("zptime=(.*?)&").findall(requestline)
            
            if len(self.faceid) == 1 and len(self.puid) == 1 and len(self.url) == 1 and len(self.zptime) == 1:
                # 字符串
                self.faceid = self.faceid[0]
                self.puid = self.puid[0]
                self.url = self.url[0]
                self.zptime = self.zptime[0]
            else:
                Hiklogging.error(str(self.client_address) + ": " + requestline + " requestline not correct")
                self.response_UploadFail("requestline not correct")
                return
            if noresponse==1:
                ipaddr = self.client_address[0]                                            
                if ipaddr not in registerIPs.keys(): 
                    registerIPs[ipaddr] = [1] # 图片数据包总数
                else:
                    registerIPs[ipaddr] = [registerIPs[ipaddr][0]+1] # 图片数据包总数
                picResult = " {}:\n\t数据包数量:{}\n".format(ipaddr,registerIPs[ipaddr][0])
                Hiklogging.info(str(self.client_address)+": "+ picResult) 
                self.response_Ok(self.url, self.puid, self.faceid)
                return

            """
            Host: 10.90.24.2:8082
            Content-Type:multipart/form-data; boundary=---------------------------7daf10c20d06
            Content-Length:299785
            """
            #Hiklogging.info(str(self.client_address) +": "+self.headers)
            boundary = ""
            content_length = 0
            
            if not os.path.isdir('./hik/pics/'+ self.client_address[0]):
                try:
                    os.makedirs('./hik/pics/'+ self.client_address[0])
                    Hiklogging.info(str(self.client_address) +": "+"创建目录：" + './hik/pics/'+ self.client_address[0])
                except Exception as e:
                    Hiklogging.warning(str(self.client_address) +": "+"创建目录：" + './hik/pics/'+ self.client_address[0])
                    
            jpg_dir = './hik/pics/'+ self.client_address[0] + '/'
            try:
                content_type = self.headers["Content-Type"]
            except Exception as e:
                Hiklogging.error(str(self.client_address) +": "+str(e))
                self.response_UploadFail("Content-Type not correct")
                return
            else:
                if "boundary=" in content_type:
                    boundary_tag = content_type.find("boundary=")
                    boundary = content_type[boundary_tag+len("boundary="):]
                    if "Content-Length" in self.headers:
                        try:
                            content_length = int(self.headers["Content-Length"])
                        except Exception as e:
                            Hiklogging.error(str(self.client_address) + ": " + "Content-Length is not digital")
                            Hiklogging.error(str(self.client_address) + ": " + str(e))
                            self.response_UploadFail("Content-Length is not digital")
                            return
                        else:
                            #Hiklogging.info(str(self.client_address) +": "+"content_length=%d" % content_length)

                            """ 图片属性
                            ---------------------------7daf10c20d06
                            Content-Disposition: form-data; name="userfile"; 
                            pictype=1&isurl=0&piclen=248896;filename="123_01_20190402132346436_1_1.jpg"
                            Content-Type:image/pjpeg
                            """
                            try:
                                rcv_bytes = self.rfile.read(content_length)
                            except Exception as e:
                                Hiklogging.error(str(self.client_address) + ": " + "receive content error")
                                Hiklogging.error(str(self.client_address) + ": " + str(e))
                                self.response_UploadFail("receive content error")
                                return
                            else:
                                rcv_len = len(rcv_bytes)
                                Hiklogging.info(str(self.client_address) +": "+"content_length={},rcv_len={}".format(content_length,rcv_len))
                                try:
                                    boundary = boundary.encode("utf8")
                                except Exception as e:
                                    Hiklogging.error(str(self.client_address) + ": " + "bytes to char error")
                                    Hiklogging.error(str(self.client_address) + ": " + str(e))
                                    self.response_UploadFail("bytes to char error")
                                    return
                                else:
                                    if rcv_len == content_length:
                                        # 解析图像属性,根据boundary划分多个图片
                                        jpg_list = rcv_bytes.split(boundary)

                                        for jpg in jpg_list:
                                            # 图片属性
                                            t1 = jpg.find("Content-Disposition".encode("utf8"))
                                            t2 = jpg.find("Content-Type:image/pjpeg".encode("utf8"))

                                            if t2 > t1 and t1 >= 0 and t2 >= 0:
                                                self.picNums += 1
                                                t2 += len("Content-Type:image/pjpeg".encode("utf8"))
                                                jpghead = jpg[t1:t2]  # jpg属性
                                                jpgdata = jpg[t2:]  # jpg数据
                                                try:
                                                    jpgstr = jpghead.decode("utf8")
                                                    Hiklogging.info(str(self.client_address) + ": " + jpgstr)
                                                except Exception as e:
                                                    Hiklogging.error(str(self.client_address) + ": " + "jpghead char to bytes error")
                                                    Hiklogging.error(str(self.client_address) + ": " + str(e))
                                                    self.response_UploadFail("jpghead char to bytes error")
                                                    return
                                                else:
                                                    filename = re.compile('filename="(.*?)"').findall(jpgstr)
                                                    if len(filename) == 1:
                                                        filename = filename[0]
                                                        filename = jpg_dir + filename
                                                        piclenlist = re.compile('&piclen=(.*?);').findall(jpgstr)
                                                        if len(piclenlist) == 1:
                                                            piclen = int(piclenlist[0])
                                                            Hiklogging.info(str(self.client_address) +": "+"filename={},图片大小piclen={}".format(filename,piclen))
                                                            if os.path.isfile(filename):
                                                                err_log = "当前目录有重名图片:{}".format(filename)
                                                                Hiklogging.warning(str(self.client_address) + ": " + err_log)
                                                                self.repeatpicsum += 1
                                                                #self.response_UploadFail(err_log)
                                                                #return
                                                            if piclen == 0:
                                                                self.zeropicsum +=1 # 图片大小为0的数量
                                                                self.findPicNums += 1    
                                                                self.savedata(filename, b'')
                                                                Hiklogging.error(str(self.client_address) +": "+ "图片大小piclen = 0")
                                                            else:
                                                                #jpg_head = jpgdata.find(b'\xff\xd8')
                                                                jpg_head = 4
                                                                jpg_len = len(jpgdata) - jpg_head
                                                                #Hiklogging.info(str(self.client_address) +": " + "jpg_len={},piclen={}".format(jpg_len,piclen))
                                                                
                                                                if jpg_head >= 0 and jpg_len >= piclen:
                                                                    if jpgdata[jpg_head: jpg_head + 2] == b'\xff\xd8' and jpgdata[jpg_head + piclen - 2: jpg_head + piclen] == b'\xff\xd9':
                                                                        jpg_Alldata = jpgdata[jpg_head : jpg_head+piclen]
                                                                        if save_jpg == 1:
                                                                            len1 = self.savedata(filename, jpg_Alldata)
                                                                            Hiklogging.info(str(
                                                                                        self.client_address) + ": " + "保存图片长度={},piclen={}".format(len1,piclen))
                                                                        self.findPicNums += 1
                                                                    else:
                                                                        Hiklogging.warning(str(
                                                                            self.client_address) + ": " + "注意:{}格式错误,开始2字节={},结束2字节={}".format(
                                                                            filename, jpgdata[jpg_head: jpg_head + 2],jpgdata[jpg_head + piclen - 2: jpg_head + piclen]))
                                                                        jpg_Alldata = jpgdata[jpg_head : jpg_head+piclen]          
                                                                        len1 = self.savedata(filename, jpg_Alldata)
                                                                        Hiklogging.info(str(
                                                                                    self.client_address) + ": " + "保存图片，长度len1={},piclen={}".format(len1,piclen))
                                                                        self.findPicNums += 1
                                                                        self.errpicsum +=1 # 错误图片数量
                                                                        if check_jpg == 1:
                                                                            self.response_UploadFail("jpg format or length not correct")
                                                                            return                                                                       
                                                                else:                                                               
                                                                    Hiklogging.warning(str(
                                                                        self.client_address) + ": " + "jpg_head:{},jpg_len:{},piclen:{}".format(
                                                                        jpg_head, jpg_len,piclen))
                                                                    Hiklogging.warning(str(
                                                                        self.client_address) + ": " + "注意：jpg format or length not correct")                                           
                                                                    len1 = self.savedata(filename, jpgdata)
                                                                    Hiklogging.warning(str(
                                                                                self.client_address) + ": " + "保存图片，长度len1={},piclen={}".format(len1,piclen))
                                                                    self.findPicNums += 1
                                                                    self.errpicsum +=1 # 错误图片数量
                                                                    if check_jpg == 1:
                                                                        self.response_UploadFail("jpg format or length not correct")
                                                                        return
                                                        else:
                                                            Hiklogging.error(str(
                                                                self.client_address) + ": " + "piclen is not digital")
                                                            self.response_UploadFail("piclen is not digital")
                                                            return
                                                    else:
                                                        Hiklogging.error(str(
                                                            self.client_address) + ": " + "filename= not correct")
                                                        self.response_UploadFail("filename= not correct")
                                                        return

                                            # 文件属性
                                            t3 = jpg.find("Content-Disposition".encode("utf8"))
                                            t4 = jpg.find("Content-Type: text/plain".encode("utf8"))
                                            if t4 > t3 and t3 >= 0:
                                                t4 += len("Content-Type: text/plain".encode("utf8"))
                                                texthead = jpg[t3:t4]  # 文件属性
                                                textdata = jpg[t4:]  # 文件数据
                                                try:
                                                    textstr = texthead.decode("utf8")
                                                except Exception as e:
                                                    Hiklogging.error(
                                                        str(self.client_address) + ": " + "texthead char to bytes error")
                                                    Hiklogging.error(str(self.client_address) + ": " + str(e))
                                                    self.response_UploadFail("texthead char to bytes error")
                                                    return
                                                else:
                                                    filename = jpg_dir + self.zptime + ".txt"
                                                    # 取数字
                                                    datalenlist = re.compile(r'(?<=datalen=)\d+\.?\d*').findall(textstr)
                                                    if len(datalenlist) == 1:
                                                        datalen = int(datalenlist[0])
                                                        Hiklogging.info(str(self.client_address) + ": filename={},datalen={}".format(filename,datalen))
                                                        if os.path.isfile(filename):
                                                            err_log = "当前目录有重名txt文件:{}".format(filename)
                                                            Hiklogging.warning(str(self.client_address) + ": " + err_log)
                                                            self.repeattxtsum+=1
                                                            #self.response_UploadFail(err_log)
                                                            #return
                                                        if datalen == 0:
                                                            self.findTxtNums += 1                                                       
                                                            self.savedata(filename, b'')
                                                            Hiklogging.warning(str(self.client_address) + ": " + "datalen = 0")
                                                        else:
                                                            try:
                                                                text_dict = json.loads(textdata[4:4+datalen].decode("utf8"))
                                                            except Exception as e:
                                                                Hiklogging.error(str(self.client_address) + ": " + str(e))
                                                                Hiklogging.error(str(self.client_address) + ": " + "textdata json format error")
                                                                Hiklogging.error("textdata :")
                                                                Hiklogging.error(textdata)
                                                                self.response_UploadFail("textdata json format error")
                                                                return
                                                            else:
                                                                if save_jpg == 1:
                                                                    self.savedata(filename, textdata[4:4+datalen])
                                                                self.findTxtNums += 1
                                                    else:
                                                        Hiklogging.error(str(
                                                            self.client_address) + ": " + "datalen= not digital")
                                                        self.response_UploadFail("datalen= not digital")
                                                        return
                                        if self.findPicNums > 0 and self.picNums == self.findPicNums and self.findTxtNums > 0:
                                            Hiklogging.info(str(self.client_address) +": "+"faceid:{},共{}张图片,共{}个文件".format(self.faceid,self.findPicNums,self.findTxtNums))
                                            self.response_Ok(self.url, self.puid, self.faceid)
                                            
                                            ipaddr = self.client_address[0]
                                            self.cal_result(ipaddr)
                                            return
                                        else:
                                            Hiklogging.error(str(self.client_address) + ": " + "应收{}张图片,实际{}张图片".format(self.picNums,self.findPicNums))
                                            Hiklogging.error(str(self.client_address) + ": " + "共{}个文件".format(self.findTxtNums))
                                            self.response_UploadFail("recv pic and txt not enough")
                                            return
                                    else:
                                        Hiklogging.error(str(self.client_address) + ": " + "rcv_len:{},content_length:{}".format(rcv_len,content_length))
                                        Hiklogging.error(str(self.client_address) + ": " + "receive content len not correct")
                                        self.response_UploadFail("receive content len not correct")
                                        return

                    else:
                        Hiklogging.error(str(self.client_address) + ": " + "Content-Length not in Headers")
                        Hiklogging.error(str(self.client_address) + ": " + self.headers)
                        self.response_UploadFail("Content-Length not in Headers")
                        return
                else:
                    Hiklogging.error(str(self.client_address) + ": " + "boundary= not in Content-Type")
                    Hiklogging.error(str(self.client_address) + ": " + content_type)
                    self.response_UploadFail("boundary= not in Content-Type")
                    return
        except Exception as e:
            Hiklogging.error(str(self.client_address) + ": " + "Exception:" + str(e))
            self.response_UploadFail("Exception:"+str(e))


class echorequestserver(socketserver.BaseRequestHandler):
    def handle(self):        
        Hiklogging.info(str(self.client_address)+": "+'TCP 连接')
        conn = self.request
        msg = 'abc'
        t=0.1
        closesocket=1
        if os.path.isfile("hikTCP.ini"):
            conf = configparser.ConfigParser()
            conf.read('hikTCP.ini')
            try:
                msg = conf.get("other",'msg')  
                t = conf.get("other",'responsetime')  
                closesocket = conf.get("other",'closesocket')  
                closesocket=int(closesocket)
            except Exception as e:
                Hiklogging.error(str(self.client_address) +": " + str(e))  
        conn.settimeout(float(t)) 
        bytes_data = b''
        while True:
            try:
                sock_data = conn.recv(1024)
                if not sock_data:
                    break
                #bytes_data += sock_data
            except Exception as e:
                #Hiklogging.warning(str(self.client_address)+": "+str(e))   
                break
        try:
            Hiklogging.info(str(self.client_address) +": TCP返回消息：" + msg)   
            back_data = msg.encode('utf8')
            conn.sendall(back_data) 
        except Exception as e:
            Hiklogging.error(str(self.client_address) +": 发数据异常：" + str(e))
        if closesocket:
            conn.close()    
                
def mkdir():
    if not os.path.isdir("hik/log"):
        os.makedirs("hik/log")
    if not os.path.isdir("hik/pics"):
        os.makedirs("hik/pics")
        
class HIK():
    def __init__(self):
        mkdir()
        self.introMsg = 'HIK服务器信息\n'
        self.introMsg += "***********************************" + '\n'
        self.introMsg += "server version is %s"%VERSION + '\n'
        self.introMsg += "***********************************" + '\n'        
        self.introMsg += "-------------------------------------------------" + '\n'
        self.introMsg += "图片和log存放目录：./hik/pics/前端ip地址/" + '\n'
        self.introMsg += "图片命名：filename" + '\n'
        self.introMsg += "文件命名：zptime.txt" + '\n'
        self.introMsg += "-------------------------------------------------"   + '\n'      
        mkdir()
        print(self.introMsg)
        # 说明信息
        self.infomsg = '说明信息:\n'

    def run(self, IP, PORT):
        global httpd
        global _running
        if threadNumsLock.locked():
            threadNumsLock.release()
        init_loggingSetHik()
        Hiklogging.info(self.introMsg)
        _running = True        
        try:                    
            if os.path.isfile("hikTCP.ini"):
                infomsg = '使用 hikTCP.ini中定义消息'            
                Hiklogging.info(infomsg)
                httpd = socketserver.ThreadingTCPServer((IP, PORT), echorequestserver)  
            else:
                httpd = socketserver.ThreadingTCPServer((IP, PORT), Handler)
            # httpd = socketserver.TCPServer((IP, PORT), Handler)
            allThreads.clear()
            registerIPs.clear()
            server_runtime[0] = time.time()
            Hiklogging.info('删除所有设备的注册信息')  
            Hiklogging.info('HIK服务器已启动，IP地址,端口:(%s , %d)'%(IP, PORT))
            httpd.serve_forever()
        except Exception as e:
            Hiklogging.error('HIK服务器启动失败，IP地址,端口:(%s , %d)'%(IP, PORT) + ", " + str(e))
   
    def stop(self):
        global _running
        if threadNumsLock.locked():
            threadNumsLock.release()
        _running = False
        if httpd == 0:
            pass
        elif httpd.fileno()>0:    
            httpd.shutdown()        
            httpd.server_close()       
            Hiklogging.info("HIK服务器已停止") 
           
def fetch_device(deviceips): 
    msg =''
    if server_runtime[0] > 0:
        #msg += '服务器启动时间：%s\n'%time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(server_runtime[0]))
        msg += 'HIK服务器启动时间：%s\n'%str(datetime.datetime.fromtimestamp(server_runtime[0]))
    else:
        msg += 'HIK服务器未启动\n'
        return msg
    #msg += '当前时间: %s\n'%time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
    msg += '当前时间: %s'%str(datetime.datetime.now())    
    if len(deviceips.strip()) == 0:
        iplist = registerIPs.keys()
    else:
        iplist = deviceips.split(';') 
    for ip in iplist: 
        ip = ip.strip()
        if ip:
            results = registerIPs.get(ip)
            if results == None:  # 没有注册
                msg += "\n\t%s not pics"%ip
            else:
                # 图片数据包总数, 图片总数量，txt总数量,错误图片数量,图片大小为0的数量     
                if len(results)==1:         
                    msg += "\n\t{}:\n\t    数据包数量:{}".format(ip,results[0])         
                elif len(results)>1:        
                    msg += "\n\t{}:\n\t    数据包数量:{}".format(ip,results[0])
                    msg += "\n\t    图片总数量:{},txt总数量:{}".format(results[1],results[2])
                    msg += "\n\t    [其中错误图片:{},大小为0的图片:{},重名图片:{},重名txt:{}]".format(results[3],results[4],results[5],results[6])                         
    msg += '\n'
    Hiklogging.info(msg)  
    return msg
      
if __name__ == "__main__":    
    IP = input("IP地址(回车默认本机IP):")
    PORT = input("端口(回车默认端口8082):")    
    if PORT=="":
        PORT = "8082"
    if IP == "":
        IP =""

    inp = input("是否保存图片（回车默认不保存）")
    if inp=="":
        save_jpg = 0
    else:
        save_jpg = 1
    inp = input("是否判断图片格式（回车默认不检测）")
    if inp=="":
        check_jpg = 0
    else:
        check_jpg = 1
    PORT = int(PORT)
    hik = HIK()
    hik.run(IP,PORT)
    
